package com.oschina.basic.multi;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Semaphore;

public class BoundHashSet<T> {

	private final Set<T> set;
	private final Semaphore sem;

	public BoundHashSet(int bound) {
		sem = new Semaphore(bound);
		this.set = Collections.synchronizedSet(new HashSet<T>());
	}

	public synchronized boolean add(T o) throws InterruptedException {
		sem.acquire();
		boolean wasAdded = false;
		try {
			wasAdded = set.add(o);
			return wasAdded;
		} finally {
			if (!wasAdded) {
				sem.release();
			}
		}
	}

	public synchronized boolean remove(T o) {
		boolean removed = set.remove(o);
		if (removed) {
			sem.release();
		}
		return removed;

	}

	@Override
	public String toString() {
		StringBuilder s = new StringBuilder("[");
		for (T t : set) {
			s.append(t.toString()).append(", ");
		}
		s.append("]");
		return s.toString();
	}

	public static void main(String[] args) {
		final int n = 10;
		final BoundHashSet<Integer> set = new BoundHashSet<Integer>(5);
		Thread add = new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < n; i++) {
					try {
						boolean wasAdded = set.add(i);
						if (wasAdded) {
							System.out.println("add to set " + i + "   "
									+ set);
						} else {
							System.out.println("failed add to set " + i);
						}
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

			}
		});
		Thread remove = new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < n; i++) {
					boolean removed = set.remove(i);
					if (removed) {
						System.out.println("remove " + i + "  " + set);
					} else {
						System.out.println("failed remove " + i);
						i--;
					}

				}

			}
		});

		add.start();
		remove.start();


	}

}

